﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.ServiceModel.Activation;
using System.Collections.ObjectModel;
using System.Web;
using System.IO;


namespace LiveService
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class LService : ILService
    {
        public static String errmsg;
        #region Explorer entities

        // Returns the user's computers
       public List<Folder> getUserComputers(System.Guid userid)
        {
            try
            {
                LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();
                List<Folder> userComp = new List<Folder>();

                IQueryable<Folder> computers = from elements in db.Folder
                                                 where elements.ownerid == userid && elements.foldertype == 1
                                                 select elements;

                userComp = computers.ToList<Folder>();
                return userComp;
            }
            catch (Exception ex)
            {
                LService.errmsg = ex.Message;
                return null;
            }
        }

        // Returns the computer's folders
       public List<Folder> getComputerFolders(System.Guid folderid)
        {
            try
            {
                LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();
                List<Folder> compFolds = new List<Folder>();

                IQueryable<Folder> compfolds = from elements in db.Folder
                                               where elements.parentid == folderid
                                               select elements;

                compFolds = compfolds.ToList<Folder>();
                return compFolds;
            }
            catch (Exception ex)
            {
                LService.errmsg = ex.Message;
                return null;
            }
        }

        // Returns the folder's file
       public List<File> getFolderFiles(System.Guid folderid)
        {
            try
            {
                LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();
                List<File> foldFiles = new List<File>();

                IQueryable<File> ffiles = from elements in db.File
                                               where elements.folderid == folderid
                                               select elements;

                foldFiles = ffiles.ToList<File>();
                return foldFiles;
            }
            catch (Exception ex)
            {
                LService.errmsg = ex.Message;
                return null;
            }
        }

        // Returns the folder's subfolders
       public List<Folder> getFolderFolders(System.Guid folderid)
        {
            try
            {
                LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();
                List<Folder> subFolds = new List<Folder>();

                IQueryable<Folder> sfolds = from elements in db.Folder
                                               where elements.parentid == folderid
                                               select elements;

                subFolds = sfolds.ToList<Folder>();
                return subFolds;
            }
            catch (Exception ex)
            {
                LService.errmsg = ex.Message;
                return null;
            }
        }

       public Folder getFolderById(System.Guid fid)
       {
           try
           {
               LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();
               Folder fold = db.Folder.Single(c => c.id == fid);
               return fold;
           }
           catch (Exception ex)
           {
               LService.errmsg = ex.Message;
               return null;
           }

       }

       public bool removeFolder(System.Guid fid)
       {
           try
           {
               LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();
               Folder fold = db.Folder.Single(c => c.id == fid);
               db.Folder.DeleteOnSubmit(fold);
               db.SubmitChanges();
               return true;
           }
           catch (Exception ex)
           {
               LService.errmsg = ex.Message;
               return false;
           }

       }
        #endregion

        #region User Management
        // True if new user is registred
       public bool registerNewUser(User user, String primary)
        {
            try
            {
                bool result = true;
                LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();

                var users = from elements in db.User
                            where elements.login == user.login || elements.email == user.email
                            select elements;

                if (users.Count() > 0)
                    result = false; 
                else
                {
                    user.createdon = DateTime.Now;
                    user.profil = "user";
                    user.id = System.Guid.NewGuid();
                    db.User.InsertOnSubmit(user);
                    db.SubmitChanges();

                    User cuser = this.getUserProfileByLogin(user.login);
                    Folder fprimary = new Folder();
                    fprimary.internalpath = "root-computer";
                    fprimary.id = System.Guid.NewGuid();
                    fprimary.name = primary;
                    fprimary.parentid = System.Guid.Parse("00000000-0000-0000-0000-000000000000");
                    fprimary.foldertype = 1;
                    fprimary.ownerid = cuser.id;
                    this.createNewUserFolders(cuser, fprimary.name.Trim());
                    this.createNewFolder(cuser, fprimary);
                }
                return result;
            }
            catch (Exception ex)
            {
                LService.errmsg = ex.Message;
                return false;
            }
        }

       public bool createNewFolder(User user, Folder fold)
       {
           try
           {
               // Creation folder en base
               LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();
               Folder newFold = new Folder();
               
               newFold.id = fold.id;
               newFold.iconpath = fold.iconpath;
               newFold.lastmodified = fold.lastmodified;
               newFold.name = fold.name;
               newFold.ownerid = fold.ownerid;
               newFold.parentid = fold.parentid;
               newFold.foldertype = fold.foldertype;

               System.Guid? pid = newFold.parentid;
               Folder parent = db.Folder.SingleOrDefault(c => c.id == pid);

               try
               {
                   if (System.IO.Directory.Exists(parent.internalpath) == true)
                   {
                       newFold.internalpath = System.IO.Path.Combine(parent.internalpath.Trim(), newFold.name.Trim());
                       System.IO.Directory.CreateDirectory(System.IO.Path.Combine(parent.internalpath.Trim(), newFold.name.Trim()));
                       db.Folder.InsertOnSubmit(newFold);
                       db.SubmitChanges();
                       LService.errmsg = null;
                       return true;
                   }
                   else { LService.errmsg = "final DB INSERT : " + System.IO.Path.Combine(parent.internalpath.Trim(), newFold.name.Trim()); return false; }
               }
               catch (Exception ex)
               {
                   LService.errmsg =  "final folder error DB INSERT : " +  System.IO.Path.Combine(parent.internalpath.Trim(), newFold.name.Trim()) + " : " + ex.Message;
                   return false;
               }
           }
           catch (Exception ex)
           {
               LService.errmsg =  "final folder error MAIn : " + ex.Message;
               return false;
           }
       }

        // Returns true if credentials are valids
       public bool authenticateUser(User user)
        {
            bool result = false;
            try
            { 
                LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();

                IQueryable<User> query = from elem in db.User
                            where elem.login == user.login && elem.password == user.password
                            select elem;
                if (query.Count() != 0)
                    result = true;
                return result;
            }
            catch (Exception ex)
            {
                LService.errmsg = ex.Message;
                return result;
            }
        }

       public bool updateUser(User user)
       {
           try
           {
               LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();
               User updateduser = db.User.Single(c => c.id == user.id);
               updateduser.lastname = user.lastname;
               updateduser.login = user.login;
               updateduser.password = user.password;
               updateduser.profil = user.profil;
               updateduser.firstname = user.firstname;
               updateduser.email = user.email;
               updateduser.avatar = user.avatar;
               db.SubmitChanges();
               return true;
           }
           catch (Exception ex)
           {
               LService.errmsg = ex.Message;
               return false;
           }
       }

        // Returns the user's profile
       public User getUserProfileById(System.Guid userid)
        {
            try
            {
                User retuser = new User();
                LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();

                var auser = from elem in db.User
                          where elem.id == userid
                          select elem;

                retuser = auser.FirstOrDefault<User>();   
                return retuser;
            }
            catch (Exception ex)
            {
                LService.errmsg = ex.Message;
                return null;
            }
        }

       // Returns the user's profile
       public User getUserProfileByLogin(String login)
       {
           try
           {
               LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();
               User retuser = new User();

               var auser = from elem in db.User
                           where elem.login == login
                           select elem;

               retuser = auser.FirstOrDefault<User>();
               return retuser;
           }
           catch (Exception ex)
           {
               LService.errmsg = ex.Message;
               return null;
           }
       }

        // Returns the user's friends
       public List<User> getUserFriends(System.Guid userid)
        {
            try
            {
                LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();
                List<User> userFriends = new List<User>();

                // on recupere les entrees avec userid = user param
                IQueryable<User_Friend> ufriends = from elements in db.User_Friend
                                                   where elements.userid == userid
                                                   select elements;

                // pour chaque on recupere celui dont id = friendid
                foreach (User_Friend tmpuser in ufriends)
                {
                    IQueryable<User> tmpu = from elements in db.User
                                             where elements.id == tmpuser.friendid
                                             select elements;
                    userFriends.Add(tmpu.FirstOrDefault<User>());
                }
                return userFriends;
            }
            catch (Exception ex)
            {
                LService.errmsg = ex.Message;
                return null;
            }
        }
        #endregion

        #region File

       private bool createNewUserFolders(User user, string primary)
       {
           bool result = true;

           try
           {
               string currentFolder = System.AppDomain.CurrentDomain.BaseDirectory;
               string parentFolder = System.IO.Path.GetPathRoot(currentFolder);
               string finalFolder = System.IO.Path.Combine(parentFolder, System.IO.Path.Combine("inetpub", @"MyLiveMesh\ClientBin\Files"));

               if (System.IO.Directory.Exists(finalFolder) == true)
               {
                   LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();
                   try
                   {
                       string filesrootpath = System.IO.Path.Combine(finalFolder, user.login.Trim());
                       System.IO.Directory.CreateDirectory(System.IO.Path.Combine(finalFolder, filesrootpath));
                       System.IO.Directory.CreateDirectory(System.IO.Path.Combine(System.IO.Path.Combine(finalFolder, filesrootpath), primary));
                       Folder fprimary = new Folder();
                       fprimary.id = System.Guid.NewGuid();
                       fprimary.iconpath = "iconpath";
                       fprimary.createdon = System.DateTime.Now;
                       fprimary.lastmodified = System.DateTime.Now;
                       fprimary.name = primary;
                       fprimary.ownerid = user.id;
                       fprimary.parentid = System.Guid.Parse("00000000-0000-0000-0000-000000000000");
                       fprimary.foldertype = 1;
                       fprimary.internalpath = System.IO.Path.Combine(System.IO.Path.Combine(finalFolder, filesrootpath), primary);
                       db.Folder.InsertOnSubmit(fprimary);
                       db.SubmitChanges();
                       return true;
                   }
                   catch (Exception ex)
                   {
                       LService.errmsg = ex.Message;
                       return false;
                   }
               }
               else
                   result = false;
               return result;
           }
           catch (Exception ex)
           {
               LService.errmsg = ex.Message;
               return false;
           }
       }

       private String getSubdirectoryByExt(string extension)
       {
           String res = " ";
           switch (extension.Trim())
           {
               case ".wmv": case ".avi" :
                    res = "videos";
                   break;
                
                   case ".txt":
                    res = "text";
                   break;

               case ".png": case ".jpg": case ".PNG": case ".JPG":
                    res = "images";
                   break;

               case ".mp3": case ".wma":
                   res = "musics";
                    break;

               default:
                   res = ".misc";
                       break;
           }
           return res;
       }

        private String getUserBasePath(String userlogin)
        {
             string currentFolder = System.AppDomain.CurrentDomain.BaseDirectory;
             string parentFolder = System.IO.Path.GetPathRoot(currentFolder);
             string finalFolder = System.IO.Path.Combine(parentFolder, System.IO.Path.Combine("inetpub", @"MyLiveMesh\Clientbin\Files"));
             string userfolder = System.IO.Path.Combine(finalFolder, userlogin);
            return userfolder;
        }

        public byte[] getServerFile(String ulogin, System.Guid parentid, String filename)
        {
            Byte[] result = null;

            try
            {
                LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();
                //File file = db.File.Single(c => c.folderid == parentid && c.name.Trim() == filename.Trim());
                var  files = from elements in db.File                          
                             where elements.folderid == parentid && elements.name.Trim() == filename.Trim()
                             select elements;

                File file = files.FirstOrDefault<File>();
                if (file.name.Trim() == filename.Trim())
                {
                    /*string loginBase = System.IO.Path.Combine(this.getUserBasePath(ulogin.Trim()),
                                                              this.getSubdirectoryByExt(file.extension.Trim()));*/
                    Folder fold = db.Folder.SingleOrDefault(c => c.id == file.folderid);

                    if (System.IO.Directory.Exists(fold.internalpath))
                    {
                        string filepath = System.IO.Path.Combine(fold.internalpath, filename.Trim());
                        if (System.IO.File.Exists(filepath))
                            result = System.IO.File.ReadAllBytes(filepath);
                        else
                            LService.errmsg = "File " + filepath + " does not exist on server !";
                    }
                    else
                        LService.errmsg = "File's directory : " + fold.internalpath + " does not exist on server !";
                }
                else
                    LService.errmsg = "No elements in database !";
                return result;
            }
            catch (Exception ex)
            {
                LService.errmsg = ex.Message;
                return null;
            }
        }


        private bool createOnServerUploadedFile(string filename, string content, string finalFolder)
        {
            try
            {
                if (content.Length > 0)
                {
                    Byte[] fb = System.Text.Encoding.UTF8.GetBytes(content);
                    FileStream fs = new FileStream(finalFolder + @"\" + filename, FileMode.OpenOrCreate);
                    fs.Write(fb, 0, fb.Length);
                    fs.Flush();
                    fs.Close();
                    return true;
                }
                else
                {
                    LService.errmsg = "on retourne false dans creations sur le serveur";
                    return false;
                }
            }
            catch (Exception e)
            {
                LService.errmsg = "on catch : " + e.Message + e.InnerException;
                return false;
            }
        }


        private bool insertInDbUploadedFile(System.Guid parentid, File file, System.Guid idUser, string finalFolder)
        {
            try
            {
                LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();
                file.createdon = DateTime.Now;
                file.folderid = parentid;
                file.id = System.Guid.NewGuid();
                file.internalpath = finalFolder.Trim();
                db.File.InsertOnSubmit(file);
                db.SubmitChanges();
                return true;
            }
            catch (Exception e)
            {
                LService.errmsg = "+++++++ ERREUR DANS LA BASE +++++" + e.Message;
                return false;
            }
        }

        private string getPathOfFile(File info, System.Guid idUser)
        {

            string finalFolder = this.getUserBasePath(this.getUserProfileById(idUser).login);
            finalFolder = System.IO.Path.Combine(finalFolder, getSubdirectoryByExt(info.extension)); 

            return finalFolder;
        }

        public bool createUploadedFile(System.Guid parentid, File info, byte[] datas, System.Guid idUser)
        {
            bool result = false;
            try
            {
                LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();
            
                Folder fold = db.Folder.SingleOrDefault(c => c.id == parentid);
                string finalFolder = fold.internalpath;
                try
                {
                    if (System.IO.Directory.Exists(finalFolder))
                    {
                        using (FileStream fs = System.IO.File.Create(string.Format("{0}{1}", finalFolder + @"\", info.name.Trim())))
                        {
                            fs.Write(datas, 0, datas.Length);
                        }
                        result = this.insertInDbUploadedFile(parentid, info, idUser, finalFolder + @"\" + info.name);
                        return true;
                    }
                    else
                        return false;
                }
                catch (Exception e)
                {
                    LService.errmsg = "on catch : " + e.Message + e.InnerException;
                    return false;
                }

                //*********************************

                /*string finalPath = getPathOfFile(info, idUser);
                if ((result = this.createOnServerUploadedFile(info.name, content, finalPath)))
                    result = this.insertInDbUploadedFile(parentid, info, idUser, finalPath);*/
            }
            catch (Exception ex)
            {
                LService.errmsg += "exception catch ds createUploadedFile" + ex.Message;
                return false;
            }
        }

        public Folder getFolderParent(System.Guid curid)
        {
            try
            {
                LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();

                Folder childfold = db.Folder.SingleOrDefault(c => c.id == curid);
                Folder parentfold = db.Folder.SingleOrDefault(c => c.id == childfold.parentid);
                return parentfold;
            }
            catch (Exception ex)
            {
                LService.errmsg += "PARENT FOLDER" + ex.Message;
                return null;
            }

        }

        public string getWebFilePath(System.Guid curid)
        {
            try
            {
                LiveServiceOrmDataContext db = new LiveServiceOrmDataContext();

                Folder fold = db.Folder.SingleOrDefault(c => c.id == curid);
                string finalFolder = fold.internalpath;
                int start = finalFolder.IndexOf("Files");
                String endpath = finalFolder.Substring(start, finalFolder.Length - start);
                endpath = endpath.Replace(@"\", "/");
                String finalend = endpath.Trim();
                finalend += "/";
                return finalend;
            }
            catch (Exception ex)
            {
                LService.errmsg += "WEB PATH" + ex.Message;
                return LService.errmsg;
            }
        }


        #endregion


        #region chunk transfert

        private static ChunksReceptor receptor;

        public bool InitializeUploadReceptor(ChunksInfo infos)
        {
            try
            {
                LService.receptor = new ChunksReceptor();
                return true;
            }
            catch (Exception ex)
            {
                LService.errmsg = "INIT : " + ex.Message;
                return false;
            }
        }

        public bool ReceiveUploadChunk(byte[] datas, System.Guid Parentid, LiveService.File Fileinfo, System.Guid Userid)
        {
            if (datas.Length == 0)
            {
                LService.errmsg = "RECEIVE 54 CHUNK NULL";
                return false;
            }
            else
            {
                try
                {
                    ChunksReceptor xreceptor = new ChunksReceptor();
                    xreceptor.ReceiveChunk(datas, Parentid, Fileinfo, Userid);
                    return true;
                }
                catch (Exception ex)
                {
                    LService.errmsg = "RECEIVE 47: " + ex.Message;
                    return false;
                }
            }

        }
        #endregion

        public String getLastError() { return LService.errmsg; }

  
    }
}
